Moduł:Timeline
local Timeline = {} local colors = require('Dev:Colors') local YEAR_LENGTH = 365.2 local MONTH_LENGTH = 30.44 function Timeline.create(frame) local conf = mw.loadData('Module:'..(frame.args1 or 'TimelineData')) local container = mw.html.create('div') local background_color = colors.parse(colors.params'color-text'):invert() local timeline_padding = 5 container:css({ 'box-sizing' = 'border-box', 'display' = 'flex', 'width' = '700px', 'padding' = timeline_padding..'px', 'background-color' = background_color:hex(), 'flex-wrap' = 'wrap' }) local labels = mw.html.create('div') local labels_width = 120 local bar_height = 16 local bar_margin = 8 labels:css({ 'width' = labels_width..'px', 'text-align' = 'right', 'line-height' = bar_height..'px', 'font-size' = (0.75 * bar_height)..'px' }) for _, label in pairs(conf.dataset) do local label_elem = mw.html.create('div'):css({ 'height' = bar_height..'px', 'margin' = bar_margin..'px 0' }) if conf.style and conf.style.label_format then label_elem:wikitext((string.gsub(conf.style.label_format, '$name', label.name))) else label_elem:wikitext(label.name) end labels:node(label_elem) end container:node(labels) local chart = mw.html.create('div') local chart_margin = 10 local chart_width = 700 - (labels_width + timeline_padding*2 + chart_margin) local chart_major = colors.params'color-text' local chart_minor = colors.parse(colors.params'color-text'):alpha(50):hex() chart:css({ 'width' = chart_width..'px', 'margin-left' = (chart_margin-1)..'px', 'border-left' = '1px solid '..chart_major, 'border-bottom' = '1px solid '..chart_major, 'background' = generateBackground(conf.from, conf.till, chart_width, chart_major, chart_minor) }) local bar_background = background_color bar_background:alpha(40) local chart_from = dateToTimestamp(conf.from) local chart_till = dateToTimestamp(conf.till) local chart_diff = chart_till - chart_from for _, label in pairs(conf.dataset) do local bar_container = mw.html.create('div'):css({ 'height' = bar_height..'px', 'margin' = bar_margin..'px 0', 'background-color' = bar_background:rgb(), 'position' = 'relative' }) for _, bar in ipairs(label.bars) do local bar_from = dateToTimestamp(bar.from, conf) local bar_till = dateToTimestamp(bar.till, conf) bar_container:node(mw.html.create('div'):css({ 'height' = bar_height..'px', 'background-color' = conf.bar_typesbar.bar_type.color, 'position' = 'absolute', 'left' = (((bar_from - chart_from)/chart_diff)*chart_width)..'px', 'right' = (((chart_till - bar_till)/chart_diff)*chart_width)..'px' })) end chart:node(bar_container) end container:node(chart) local chart_timeline = mw.html.create('div'):css({ 'width' = chart_width..'px', 'height' = (0.75 * bar_height)..'px', 'line-height' = (0.75 * bar_height)..'px', 'margin-left' = (labels_width + chart_margin)..'px', 'font-size' = (0.625 * bar_height)..'px', 'position' = 'relative' }) for i = math.floor(chart_from/(60*60*24*YEAR_LENGTH)) + 1, math.floor(chart_till/(60*60*24*YEAR_LENGTH)), 1 do chart_timeline:node(mw.html.create('div'):wikitext(1970+i):css({ 'position' = 'absolute', 'left' = (((dateToTimestamp('01/01/'..(1970+i)) - chart_from)/chart_diff)*chart_width)..'px', 'transform' = 'translate(-50%, 0)' })) end container:node(chart_timeline) local legend = mw.html.create('div'):css({ 'margin-top' = bar_height..'px', 'margin-left' = (labels_width + chart_margin)..'px', 'font-size' = (0.75*bar_height)..'px', 'width' = chart_width..'px', 'display' = 'flex', 'flex-wrap' = 'wrap' }) for _, bar_type in pairs(conf.bar_types) do if bar_type.legend then local label_elem = mw.html.create('div'):css({ 'display' = 'flex', 'align-items' = 'center', 'height' = bar_height..'px', 'width' = (100/3)..'%' }) label_elem:node(mw.html.create('div'):css({ 'width' = (0.75*bar_height)..'px', 'height' = (0.75*bar_height)..'px', 'background-color' = bar_type.color, 'margin-right' = (bar_margin/2)..'px' })) if bar_type.order then label_elem:css('order', bar_type.order) end label_elem:wikitext(bar_type.legend) legend:node(label_elem) end end container:node(legend) return container end function generateBackground(from, till, width, year_color, month_color) local start_date = dateToTimestamp(from) local end_date = dateToTimestamp(till) local diff = end_date - start_date local offset = (60*60*24*YEAR_LENGTH) - (start_date % (60*60*24*YEAR_LENGTH)) local background = 'linear-gradient(to right, transparent' local month_start = offset % (60*60*24*MONTH_LENGTH) for i = month_start, offset - (60*60*24*MONTH_LENGTH), (60*60*24*MONTH_LENGTH) do background = background..generateBar((i/diff)*width, month_color) end while offset <= diff do background = background..generateBar((offset/diff)*width, year_color) for i = 1, 11, 1 do background = background..generateBar((offset/diff)*width + ((i * (60*60*24*MONTH_LENGTH))/diff)*width, month_color) end offset = offset + (60*60*24*YEAR_LENGTH) end background = background..', transparent)' return background end function generateBar(pos, bar) pos = math.floor(pos) return ', transparent '..pos..'px, '..bar..' '..pos..'px, '..bar..' '..(pos+1)..'px, transparent '..(pos+1)..'px' end function dateToTimestamp(d, conf) if d 'now' then return os.time() end if d 'start' and conf.from then return dateToTimestamp(conf.from) end if d 'end' and conf.till then return dateToTimestamp(conf.till) end return os.time({ year = d:sub(7, 10), month = d:sub(4, 5), day = d:sub(1, 2), hour = 0, min = 0, sec = 0 }) end return Timeline